#pragma once

#include "Utilities/ITypes.h"

class Setting;
class EffectSetting;
class TESObjectCLOT;

#ifdef OBLIVION
#include "boost/random/mersenne_twister.hpp"
#include "boost/random/uniform_int.hpp"
#include "boost/random/uniform_real.hpp"
#include "boost/random/variate_generator.hpp"

class RNG
{
public:
	static boost::mt19937 mt;
	static boost::variate_generator<boost::mt19937&, boost::uniform_int<UInt8> > flipGen;
	static boost::variate_generator<boost::mt19937&, boost::uniform_real<double> > pctGen;
	static bool flipFn();
};
#define rng RNG::mt
#define pct RNG::pctGen
#define flip RNG::flipFn()
#endif

class obseIntfcFunctor {
public:
	typedef double (obseFunction)(UInt32 val);
	obseFunction* function;

	double operator()(UInt32 val);

	obseIntfcFunctor(obseFunction* func = NULL);
};

extern obseIntfcFunctor callScptNoArgs;
extern obseIntfcFunctor getSoulLvFromLL;
extern obseIntfcFunctor addFormToSavegame;

class Souls {
public:
	static const UInt32	id_LL0LootSoulGemEmpty100 = 0x0003E4ED; // from Oblivion.esm
	enum {
		kSoulIndex_Subpetty,
		kSoulIndex_Petty,
		kSoulIndex_Lesser,
		kSoulIndex_Common,
		kSoulIndex_Greater,
		kSoulIndex_Grand,
		kSoulIndex_Ultra,
		kSoulIndex_Negative,

		kSoulIndex_MAX
	};
	enum {
		kSoulMask_Subpetty	= 1 << kSoulIndex_Subpetty,
		kSoulMask_Petty		= 1 << kSoulIndex_Petty,
		kSoulMask_Lesser	= 1 << kSoulIndex_Lesser,
		kSoulMask_Common	= 1 << kSoulIndex_Common,
		kSoulMask_Greater	= 1 << kSoulIndex_Greater,
		kSoulMask_Grand		= 1 << kSoulIndex_Grand,
		kSoulMask_Ultra		= 1 << kSoulIndex_Ultra,
		kSoulMask_Negative	= 1 << kSoulIndex_Negative,

		kSoulMask_Positive	= kSoulMask_Negative - 1,
		kSoulMask_All		= kSoulMask_Positive | kSoulMask_Negative
	};
	static UInt32	kSoulgemIDs_Array	[kSoulIndex_MAX];
private:

	typedef UInt16 (Souls::* LvFunc)() const;
	LvFunc		kSoulLvDefFuncs_Array	[kSoulIndex_MAX];
	Setting*	kSoulLvOvrGMSTs_Array	[kSoulIndex_MAX];
	UInt32		kSoulLvOvrScpts_Array	[kSoulIndex_MAX];

	typedef SInt32 (Souls::* VlFunc)() const;
	Setting*	kSoulVlDefGMSTs_Array	[kSoulIndex_MAX];
	VlFunc		kSoulVlDefFuncs_Array	[kSoulIndex_MAX];
	Setting*	kSoulVlOvrGMSTs_Array	[kSoulIndex_MAX];
	UInt32		kSoulVlOvrScpts_Array	[kSoulIndex_MAX];
	
	Souls();

public:
	~Souls();
	static void	Initialize(); // initializes all custom forms, not just soul-related.
	static void	Clear();

	UInt16 getLv(UInt8 soul) const;
	bool setLv(UInt16 level, UInt8 soul);
	bool unsetLv(UInt8 soul);

	SInt32 getVl(UInt8 soul) const;
	bool setVl(SInt32 value, UInt8 soul);
	bool unsetVl(UInt8 soul);

#define declSoulFns(lv) UInt16 getLv ## lv ## () const; bool setLv ## lv ## (UInt16 level); bool unsetLv ## lv ## (); \
						SInt32 getVl ## lv ## () const; bool setVl ## lv ## (SInt32 value); bool unsetVl ## lv ## ()

	declSoulFns(Subpetty);
	declSoulFns(Petty);
	declSoulFns(Lesser);
	declSoulFns(Common);
	declSoulFns(Greater);
	declSoulFns(Grand);
	declSoulFns(Ultra);
	declSoulFns(Negative);

	UInt16 getDefLvSubpetty() const;
	UInt16 getDefLvUltra() const;
	UInt16 getDefLvNegative() const;

	SInt32 getDefVlSubpetty() const;
	SInt32 getDefVlUltra() const;
	SInt32 getDefVlNegative() const;
};

extern Souls* kSouls;

extern EffectSetting*	FOMF;
extern EffectSetting*	DRMF;
extern Setting*			fAutoEnchantmentRateBase;
extern Setting*			fAutoEnchantmentRateMult;
extern TESObjectCLOT*	token;
